from ping3 import ping
from concurrent.futures import ThreadPoolExecutor
import tkinter as tk
import  os
#存放测试结果的字典
ips_status = dict()
ips_success = dict()
ips_failure = dict()

log = 'log/ping_tool_log.txt'
#打开日志函数需要单独修改

class ping_tool(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("New Window")
        self.geometry('800x600')
        self.minsize(800, 600)  # 最小尺寸
        self.maxsize(800, 600)  # 最大尺寸

        self.title('IP测试工具')

        ####标题####第一行####
        lb0 = tk.Label(self, text='IP测试工具', font=('黑体', 24))
        lb0.place(relx=0.1, rely=0.05, relwidth=0.8, relheight=0.1)

        ####IP地址####第二行####
        IP = tk.Label(self, text='IP地址')
        IP.place(relx=0.1, rely=0.18, relwidth=0.06, relheight=0.05)
        IP1 = tk.Entry(self)
        IP1.insert(0, "192")
        IP1.place(relx=0.17, rely=0.18, relwidth=0.06, relheight=0.05)

        IP2 = tk.Entry(self)
        IP2.insert(0, "168")
        IP2.place(relx=0.24, rely=0.18, relwidth=0.06, relheight=0.05)

        IP3 = tk.Entry(self)
        IP3.insert(0, "100")
        IP3.place(relx=0.31, rely=0.18, relwidth=0.06, relheight=0.05)

        lb4 = tk.Label(self, text='主机位范围')
        lb4.place(relx=0.4, rely=0.18, relwidth=0.1, relheight=0.05)
        IP4s = tk.Entry(self)
        IP4s.insert(0, "1")
        IP4s.place(relx=0.51, rely=0.18, relwidth=0.06, relheight=0.05)

        lb4 = tk.Label(self, text='——')
        lb4.place(relx=0.58, rely=0.18, relwidth=0.01, relheight=0.05)

        IP4e = tk.Entry(self)
        IP4e.insert(0, "254")
        IP4e.place(relx=0.6, rely=0.18, relwidth=0.06, relheight=0.05)

        ipad = tk.Button(self, text='地址合成', command=lambda: self.ipadd(IP1.get(), IP2.get(), IP3.get(), IP4s.get(), IP4e.get()))
        ipad.place(relx=0.72, rely=0.18, relwidth=0.18, relheight=0.05)

        ####第二行结束####

        ipad = tk.Button(self, text='开始测试', command=lambda: self.addpings(IP1.get(), IP2.get(), IP3.get(), IP4s.get(), IP4e.get()))
        ipad.place(relx=0.72, rely=0.25, relwidth=0.18, relheight=0.05)

        success = tk.Button(self, text='响应主机', command=lambda: self.read_success())
        success.place(relx=0.72, rely=0.32, relwidth=0.18, relheight=0.05)

        failure = tk.Button(self, text='失败主机', command=lambda: self.read_failure())
        failure.place(relx=0.72, rely=0.39, relwidth=0.18, relheight=0.05)

        openlog1 = tk.Button(self, text='打开日志', command=lambda: self.openlog())
        openlog1.place(relx=0.72, rely=0.53, relwidth=0.18, relheight=0.05)

        dellog1 = tk.Button(self, text='清空日志', command=lambda: self.dellog())
        dellog1.place(relx=0.72, rely=0.6, relwidth=0.18, relheight=0.05)

        ztxtdel = tk.Button(self, text='清空输出', command=lambda: self.txtdel())
        ztxtdel.place(relx=0.72, rely=0.74, relwidth=0.18, relheight=0.05)

        self.txt = tk.Text(self)
        self.txt.insert(0.0,
                "工具执行过程中会卡顿并无回显，请不要多次点击，耐心等待执行完成。\n")
        self.txt.place(relx=0.1, rely=0.26, relwidth=0.6, relheight=0.70)

        by = tk.Label(self, text='version：1.2  |  by:背包的小迟')
        by.place(relx=0.7, rely=0.93, relwidth=0.3, relheight=0.05)

    ######################################## 自定义函数_批量Ping ########################################
    def pings(self,ips):
        # ips为可迭代对象,每个元素为一个IP地址或域名
        # 返回值为一个字典,key保存ip,value保存是否能ping通
        global ips_status
        # 多线程执行ping函数
        with ThreadPoolExecutor(max_workers=32) as pool:
            results = pool.map(ping,ips)
        for index,result in enumerate(results):
            ip = ips[index]
            if type(result) == float:
                ips_status[ip] = True
                ips_success[ip] = True
            else:
                ips_status[ip] = False
                ips_failure[ip] = False
        return  ips_status

    ######################################## 自定义函数_批量Ping ########################################
    def ipadd(self,IP1, IP2, IP3, IP4S, IP4E):  # IP合成测试
        IP4S = int(IP4S)
        IP4E = int(IP4E) + 1
        self.txt.delete(1.0, "end")  # 清空输出
        i = 0
        ipaddress = []
        for client_ip in range(IP4S, IP4E):
            i += 1
            # 根据网段和主机合成数据
            # 合成IP地址
            address = str(IP1) + "." + str(IP2) + "." + str(IP3) + "." + str(client_ip)
            addressn = address + "\n"
            self.txt.insert(tk.END, addressn)  # 追加显示运算结果
            ipaddress.insert(i, address)
        #print("IP合成完毕")
        self.txt.insert(tk.END, "-------------------------- \n")
        return ipaddress

    def addpings(self,IP1, IP2, IP3, IP4S, IP4E):
        #打开日志文件准备追加写入
        fp = open(log, 'a')
        #每次测试前刷新结果存放字典
        global ips_status
        ips_status.clear()
        ips_success.clear()
        ips_failure.clear()
        IP4S = int(IP4S)
        IP4E = int(IP4E) + 1
        self.txt.delete(1.0, "end")  # 清空输出
        i = 0
        ipaddress = []
        for client_ip in range(IP4S, IP4E):
            i += 1
            # 根据网段和主机合成数据
            # 合成IP地址
            address = str(IP1) + "." + str(IP2) + "." + str(IP3) + "." + str(client_ip)
            ipaddress.insert(i, address)
        ips_status = self.pings(ipaddress)
        num = len(ips_status)
        success_num = len(ips_success)
        failure_num = len(ips_failure)
        b = "共测试 %d 个地址,其中%d个响应,%d个未响应 \n"%(num,success_num,failure_num)
        bb = "共测试 %d 个地址,其中%d个响应,%d个未响应" % (num, success_num, failure_num)
        print(bb,file=fp)
        self.txt.insert(tk.END, b)
        for key, value in ips_status.items():
            a = key + ": " + str(value) + "\n"
            self.txt.insert(tk.END, a)  # 追加显示运算结果
            print(key + ": " + str(value), file = fp)
        fp.close()

    def read_success(self) :
        if len(ips_status) == 0 :
            self.txt.insert(tk.END, "请先进行ping测试\n")  # 追加显示运算结果
            return
        if len(ips_success) == 0 :
            self.txt.insert(tk.END, "没有已响应的主机\n")  # 追加显示运算结果
            return
        else:
            self.txt.insert(tk.END, "已响应主机：%d 个\n"%len(ips_success))  # 追加显示运算结果
            for key, value in ips_success.items():
                a = key + ": " + str(value) + "\n"
                self.txt.insert(tk.END, a)  # 追加显示运算结果
    def read_failure(self) :
        if len(ips_status) == 0 :
            self.txt.insert(tk.END, "请先进行ping测试\n")  # 追加显示运算结果
            return
        if len(ips_failure) == 0 :
            self.txt.insert(tk.END, "没有未响应的主机\n")  # 追加显示运算结果
            return
        else:
            self.txt.insert(tk.END, "未响应主机：%d 个\n"%len(ips_failure))  # 追加显示运算结果
            for key, value in ips_failure.items():
                a = key + ": " + str(value) + "\n"
                self.txt.insert(tk.END, a)  # 追加显示运算结果



    def openlog(self):
        try:
            os.startfile('log\ping_tool_log.txt')
        except:
            self.txt.insert(tk.END, "打开失败，文件不存在 \n")


    def dellog(self):
        try:
            open(log, 'w').close()
            self.txt.insert(tk.END, "日志已清空 \n")
        except:
            self.txt.insert(tk.END, "删除失败，文件不存在 \n")

    def txtdel(self):  # 清空输出
        self.txt.delete(1.0, "end")  # 清空输出


    


